using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using NUnit.Framework;

using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;

using Demo.Model;

using Pampa.CRUD.Core;
using Pampa.Grid.Core;
using Pampa.Grid.Core.Filters;

using Pampa.GenericEntity;

namespace Pampa.GenericEntity.Test
{
    [TestFixture]
    public class GenericEntityTestCase : AbstractModelTestCase
    {
        [TestFixtureSetUp]
        public override void FixtureInit()
        {
            base.FixtureInit();
        }

        [SetUp]
        public override void Init()
        {
            base.Init();

            CreateTables();
        }

        [Test]
        public void StringProperties()
        {
            GenericEntity genericEntity = new GenericEntity();
            genericEntity.SetPropertyValue("P1", "1");
            genericEntity.SetPropertyValue("P2", "2");
            genericEntity.Save();

            GenericEntity genericEntityCopy = GenericEntity.Find(genericEntity.ID);
            Assert.AreEqual(genericEntity.GetPropertyValue("P1"), genericEntity.GetPropertyValue("P1"));
            Assert.AreEqual(genericEntity.GetPropertyValue("P2"), genericEntity.GetPropertyValue("P2"));
        }

        [Test]
        public void EntityProperties()
        {
            // Esto simula el caso de una propiedad asociada a un combo o un selector
            // La entidad hija ya esta grabada antes de llamar al setValue
            State state = new State();
            state.Description = "State 1";
            state.Save();

            GenericEntity genericEntity = new GenericEntity();
            genericEntity.SetPropertyValue("State", state);
            genericEntity.Save();

            GenericEntity genericEntityCopy = GenericEntity.Find(genericEntity.ID);
            Assert.AreEqual("State 1", genericEntityCopy.GetPropertyValue("State.Description"));
        }

        [Test]
        public void EntityProperties2()
        {
            State state = new State();
            state.Description = "State 1";
            state.Save();

            City city = new City();
            city.Description = "City 1";
            city.Save();

            GenericEntity genericEntity = new GenericEntity();
            genericEntity.SetPropertyValue("City", city);
            genericEntity.SetPropertyValue("City.State", state);
            genericEntity.Save();

            GenericEntity genericEntityCopy = GenericEntity.Find(genericEntity.ID);
            Assert.AreEqual("State 1", genericEntity.GetPropertyValue("City.State.Description"));
            Assert.AreEqual("City 1", genericEntityCopy.GetPropertyValue("City.Description"));
        }

        [Test]
        public void EntityProperties3()
        {
            Address address = new Address();
            City city = new City();
            city.Save();

            // La asignacion del address debera hacerse  en la pagina
            GenericEntity genericEntity = new GenericEntity();
            genericEntity.SetPropertyValue("Address", address);

            // Esto lo va a hacer el EntityManager
            genericEntity.SetPropertyValue("Address.City", city);
            genericEntity.SetPropertyValue("Address.City.Description", "City 1");
            genericEntity.SetPropertyValue("Address.Street", "Siempre Viva");
            genericEntity.SetPropertyValue("Address.Number", "1"); 
            genericEntity.Save();

            GenericEntity genericEntityCopy = GenericEntity.Find(genericEntity.ID);
            Assert.AreEqual("City 1", genericEntityCopy.GetPropertyValue("Address.City.Description"));
            Assert.AreEqual("Siempre Viva", genericEntity.GetPropertyValue("Address.Street"));
            Assert.AreEqual("1", genericEntity.GetPropertyValue("Address.Number"));
        }

        [Test]
        public void EntityListProperties()
        {
            State state = new State();
            state.Description = "State";
            state.Save();

            City city1 = new City();
            city1.State = state;
            city1.Description = "City 1";
            city1.Save();

            City city2 = new City();
            city2.State = state;
            city2.Description = "City 2";
            city2.Save();

            GenericEntity genericEntity = new GenericEntity();
            IList list = genericEntity.GetPropertyList("Cities", typeof(Demo.Model.City));
            list.Add(city1);
            list.Add(city2);
            genericEntity.Save();

            GenericEntity genericEntityCopy = GenericEntity.Find(genericEntity.ID);
            IList list2 = genericEntityCopy.GetPropertyList("Cities", typeof(Demo.Model.City));
            Assert.AreEqual(2, list2.Count);
            Assert.AreEqual("City 1", ((City)list2[0]).Description);
            Assert.AreEqual("City 2", ((City)list2[1]).Description);
            Assert.AreEqual("State", ((City)list2[0]).State.Description);
        }

        [Test]
        public void DataReaderGetAll()
        {
            // Genero Datos
            CreateGenericEntities();

            // Configuracion sin filtros
            Pampa.Grid.Core.Configuration configuration = new Pampa.Grid.Core.Configuration();
            GenericEntityDataReader dataAdapter = new GenericEntityDataReader("Demo");
            dataAdapter.Type = "1";
            
            // Count Test
            Assert.AreEqual(20, dataAdapter.GetCount(configuration));
        }

        [Test]
        public void DataReaderGetAllOrdered()
        {
            // Genero Datos
            CreateGenericEntities();

            // Configuracion sin filtros ordenado por prop
            Pampa.Grid.Core.Configuration configuration = new Pampa.Grid.Core.Configuration();
            Pampa.Grid.Core.ColumnConfig columnConfig = new Pampa.Grid.Core.ColumnConfig();
            columnConfig.Field = "prop";
            columnConfig.Order = Pampa.Grid.Core.OrderDirection.Ascending;
            configuration.Columns.Add(columnConfig);

            GenericEntityDataReader dataAdapter = new GenericEntityDataReader("Demo");
            dataAdapter.Type = "1";

            // Read Data
            dataAdapter.Open(configuration, 10, 1);
            dataAdapter.Read(); Assert.AreEqual(0, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(0, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(1, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(1, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(2, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(2, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(3, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(3, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(4, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual(4, dataAdapter.GetValue("prop"));
            dataAdapter.Close();
        }

        [Test]
        public void DataReaderGetAllAdvanceOrdered()
        {
            // Genero Datos
            CreateGenericEntities();

            // Configuracion sin filtros ordenado por prop
            Pampa.Grid.Core.Configuration configuration = new Pampa.Grid.Core.Configuration();

            Pampa.Grid.Core.ColumnConfig columnConfig = new Pampa.Grid.Core.ColumnConfig();
            columnConfig.Field = "prop2";
            columnConfig.Order = Pampa.Grid.Core.OrderDirection.Ascending;
            configuration.Columns.Add(columnConfig);

            columnConfig = new Pampa.Grid.Core.ColumnConfig();
            columnConfig.Field = "prop";
            columnConfig.Order = Pampa.Grid.Core.OrderDirection.Ascending;
            configuration.Columns.Add(columnConfig);

            GenericEntityDataReader dataAdapter = new GenericEntityDataReader("Demo");
            dataAdapter.Type = "1";

            // Read Data
            dataAdapter.Open(configuration, 11, 1);
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(0, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(1, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(2, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(3, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(4, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(5, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(6, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(7, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(8, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(9, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("2", dataAdapter.GetValue("prop2")); Assert.AreEqual(0, dataAdapter.GetValue("prop"));
            dataAdapter.Close();
        }
        
        [Test]
        public void DataReaderGetAllFiltered()
        {
            // Genero Datos
            CreateGenericEntities();

            // Configuracion ordenado por prop
            Pampa.Grid.Core.Configuration configuration = new Pampa.Grid.Core.Configuration();
            Pampa.Grid.Core.ColumnConfig columnConfig = new Pampa.Grid.Core.ColumnConfig();
            columnConfig.Field = "prop";
            columnConfig.Order = Pampa.Grid.Core.OrderDirection.Ascending;
            configuration.Columns.Add(columnConfig);

            // filtros
            AndGroupFilter andGroupFilter = new AndGroupFilter();
            andGroupFilter.AddFilter(new SimpleFilter("prop", OperationType.Grater, 3));
            andGroupFilter.AddFilter(new SimpleFilter("prop", OperationType.LessEqual, 7));

            OrGroupFilter orGroupFilter = new OrGroupFilter(); 
            orGroupFilter.AddFilter(andGroupFilter);
            orGroupFilter.AddFilter(new SimpleFilter("prop", OperationType.Equal, 9));

            configuration.StaticFilter.AddFilter(new SimpleFilter("prop2", OperationType.Equal, "1"));
            configuration.StaticFilter.AddFilter(orGroupFilter);

            GenericEntityDataReader dataAdapter = new GenericEntityDataReader("Demo");
            dataAdapter.Type = "1";

            // Count
            Assert.AreEqual(5, dataAdapter.GetCount(configuration));

            // Read Data
            dataAdapter.Open(configuration, 10, 1);
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(4, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(5, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(6, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(7, dataAdapter.GetValue("prop"));
            dataAdapter.Read(); Assert.AreEqual("1", dataAdapter.GetValue("prop2")); Assert.AreEqual(9, dataAdapter.GetValue("prop"));
            dataAdapter.Close();
        }

        [Test]
        public void AdditionalData()
        {
            SampleActiveRecord sampleActiveRecord = new SampleActiveRecord();

            EntityManager.SetPropertyValueFromString(sampleActiveRecord, "AdditionalData.Text", "Sample Text", null);
            Assert.AreEqual("Sample Text", EntityManager.GetPropertyValue(sampleActiveRecord, "AdditionalData.Text"));
        }
        
        [Test]
        public void AdvanceAdditionalData()
        {
            SampleActiveRecord sampleActiveRecord = new SampleActiveRecord();
            SampleActiveRecord sampleEntity2 = new SampleActiveRecord();

            sampleActiveRecord.AdditionalData.SetPropertyValue("SampleEntity", sampleEntity2);
            EntityManager.SetPropertyValueFromString(sampleActiveRecord, "AdditionalData.SampleEntity.Text", "Sample Text", null);
            EntityManager.SetPropertyValueFromString(sampleActiveRecord, "AdditionalData.SampleEntity.AdditionalData.Text", "Sample Text", null);

            Assert.AreEqual("Sample Text", EntityManager.GetPropertyValue(sampleActiveRecord, "AdditionalData.SampleEntity.Text"));
            Assert.AreEqual("Sample Text", EntityManager.GetPropertyValue(sampleActiveRecord, "AdditionalData.SampleEntity.AdditionalData.Text"));
        }

        private static void CreateTables()
        {
            string connString = System.Configuration.ConfigurationManager.ConnectionStrings["Demo"].ConnectionString;
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connString);
            conn.Open();

            System.Data.SqlClient.SqlCommand command = new System.Data.SqlClient.SqlCommand("drop table GenericProperty", conn);
            try { command.ExecuteNonQuery(); }
            catch { };

            command = new System.Data.SqlClient.SqlCommand("drop table GenericEntity", conn);
            try { command.ExecuteNonQuery(); }
            catch { };

            command = new System.Data.SqlClient.SqlCommand("CREATE TABLE [dbo].[GenericEntity]([ID] [int] IDENTITY(1,1) NOT NULL,[Type] [varchar](50) NULL, [Status] [char](1) NULL)", conn);
            command.ExecuteNonQuery();

            command = new System.Data.SqlClient.SqlCommand("CREATE TABLE [dbo].[GenericProperty]([ID] [int] IDENTITY(1,1) NOT NULL,[EntityID] [int] NULL, [ParentID] [int] NULL, [Type] [char](1) NULL, [EntityType] [varchar](255) NULL, [Name] [varchar](50) NULL, [StringValue] [varchar](1024) NULL, [BitValue] bit NULL, [NumericValue] float NULL, [DateTimeValue] datetime NULL)", conn);
            command.ExecuteNonQuery();

            conn.Close();
        }

        private static void CreateGenericEntities()
        {
            for (int i = 0; i < 10; i++)
            {
                GenericEntity genericEntity = new GenericEntity();
                genericEntity.Type = "1";
                genericEntity.SetPropertyValue("prop", i);
                genericEntity.SetPropertyValue("prop2", "1");

                genericEntity.Save();
            }

            for (int i = 0; i < 10; i++)
            {
                GenericEntity genericEntity = new GenericEntity();
                genericEntity.Type = "1";
                genericEntity.SetPropertyValue("prop", i);
                genericEntity.SetPropertyValue("prop2", "2");

                genericEntity.Save();
            }
        }

    }
}
